import { ChinaDate } from "./ChinaDate";
import { dateUtil } from "./dateUtil";
import { GanZhi } from './ganzhi'
import { JieQi } from "./jieqi";

/**
 * @description 实例化四柱对象
 * @param {Date} theDate alt 此四柱的公历日期
 * @param {ChinaDate} theChinaDate alt 此四柱的农历日期
 * @param {bool} theIsMan alt 性别
 * @param {GanZhi} theYearGZ alt 年干支
 * @param {GanZhi} theMonthGZ alt 月干支
 * @param {GanZhi} theDayGZ alt 日干支
 * @param {GanZhi} theHourGZ alt 时干支,可为空
 * @return {SiZhu}
 */
export class SiZhu {
	Date : Date
	ChinaDate : ChinaDate
	YearGZ : GanZhi
	MonthGZ : GanZhi
	DayGZ : GanZhi
	HourGZ ?: GanZhi
	IsMan : boolean
	/** 相关有争议的节气索引,如果节气没有争议时此值保持为null */
	OtherJieQiIndex ?: number
	/** 相关有争议的四柱,如果没有争议时此值保持为null */
	OtherSiZhu ?: SiZhu
	VipName : string | undefined;
	/** 大运起岁 */
	StartAge : number;
	/** 按节气计算的出生年份,有多种用途(可用来计算属相和虚岁) */
	JieQiYear : number;
	constructor(theDate : Date, theChinaDate : ChinaDate, theIsMan : boolean, theYearGZ : GanZhi, theMonthGZ : GanZhi, theDayGZ : GanZhi, theHourGZ ?: GanZhi) {
		this.Date = theDate;
		this.ChinaDate = theChinaDate;
		this.YearGZ = theYearGZ;
		this.MonthGZ = theMonthGZ;
		this.DayGZ = theDayGZ;
		this.HourGZ = theHourGZ;
		this.IsMan = theIsMan;

		var dsort = (Math.floor(this.YearGZ.DiZhi % 2) == 1) != this.IsMan;
		var ddays = 0;
		var y = theDate.getFullYear();
		var j = ((theMonthGZ.DiZhi + 11) % 12) * 2;
		if (theDate.getMonth() == 0 && theMonthGZ.DiZhi == 0) {
			y--;
		};
		var dbirthday = new Date(theDate.getFullYear(), theDate.getMonth(), theDate.getDate());
		if (theDate.getHours() >= 23) {
			dbirthday.setDate(dbirthday.getDate() + 1)
		}
		if (dsort) {
			//顺查
			j += 2;
			if (j == 24) {
				y++;
				j = 0;
			}
			var djieqidate = JieQi.getJieQi(y, j);
			var ddate = new Date(djieqidate.getFullYear(), djieqidate.getMonth(), djieqidate.getDate());
			if (dateUtil.FormatHour(djieqidate) >= 23) {
				ddate.setDate(ddate.getDate() + 1)
			}
			//ddays = parseInt((ddate - dbirthday) / (24 * 60 * 60 * 1000));
			ddays = dateUtil.GetDaysFrom(dbirthday, ddate);
		} else {
			//逆查
			var djieqidate = JieQi.getJieQi(y, j);
			var ddate = new Date(djieqidate.getFullYear(), djieqidate.getMonth(), djieqidate.getDate());
			if (dateUtil.FormatHour(djieqidate) >= 23) {
				ddate.setDate(ddate.getDate() + 1)
			}
			//ddays = parseInt((dbirthday - ddate) / (24 * 60 * 60 * 1000));
			ddays = dateUtil.GetDaysFrom(ddate, dbirthday);
		}
		var dAge = Math.round(ddays * 10 / 3) / 10;
		if (dAge < 1) dAge = 1;
		this.StartAge = dAge;
		var djieqiYear = theDate.getFullYear();
		djieqiYear += (theYearGZ.DiZhi == GanZhi.getYearGanZhi(theDate.getFullYear()).DiZhi ? 0 : -1);
		this.JieQiYear = djieqiYear;
	}
	/**
	 * @description 大运查询顺序(true=顺查,false=逆查)
	 * @return {Boolean}
	 */
	getDaYunSort() : boolean {
		return (Math.floor(this.YearGZ.DiZhi % 2) == 1) != this.IsMan;
	}
	/**
	 * @description 获取指定天干地支的六亲索引
	 * @param {int} theTianGanDay
	 * @param {int} theTianGan
	 * @return {int}
	 */
	static getLiuQinTG(theTianGanDay : number, theTianGan : number) : number {
		switch (theTianGanDay) {
			case 0:
			case 2:
			case 4:
			case 6:
			case 8: //五阳干
				return (theTianGan + (10 - theTianGanDay)) % 10;
			case 1:
			case 3:
			case 5:
			case 7:
			case 9: //'五阴干,从阳干基础下调整
				return new Array(0, 3, 2, 5, 4, 7, 6, 9, 8, 1)[(theTianGan + (10 - theTianGanDay)) % 10];
			default:
				return -1;
		}
	}
	/**
	 * @description 获取六亲的天干的文字
	 * @param {int} theTianGanDay
	 * @param {int} theTianGan
	 * @return {String}
	 */
	static getLiuQinTGText(theTianGanDay : number, theTianGan : number) : string {
		return dateUtil.LiuQinTGLine.charAt(this.getLiuQinTG(theTianGanDay, theTianGan));
	}
	/**
	 * 12生旺列表,每个势都占两个字,如果它本来是一个字,就要再去掉多余的空格
	 */
	static WangLine = "长生沐浴冠带临官帝旺 衰 病 死 墓 绝 胎 养"
	/**
	 * @description 获取地支生旺的索引
	 * @param {int} theTianGanDay
	 * @param {int} theDiZhi
	 * @return {int}
	 */
	static getWangIndex(theTianGanDay : number, theDiZhi : number) : number {
		switch (theTianGanDay) {
			case 0:
				return (theDiZhi + 1) % 12
			case 2:
			case 4:
				return (theDiZhi + 10) % 12
			case 6:
				return (theDiZhi + 7) % 12
			case 8:
				return (theDiZhi + 4) % 12
			case 1:
				return 11 - ((theDiZhi + 5) % 12)
			case 3:
			case 5:
				return 11 - ((theDiZhi + 2) % 12)
			case 7:
				return 11 - ((theDiZhi + 11) % 12)
			case 9:
				return 11 - ((theDiZhi + 8) % 12)
			default:
				return -1
		}
	}
	/**
	 * @description 获取地支生旺文本
	 * @param {int} theTianGanDay
	 * @param {int} theDiZhi
	 * @return {String}
	 */
	static getWangText(theTianGanDay : number, theDiZhi : number) : string {
		let dindex = SiZhu.getWangIndex(theTianGanDay, theDiZhi) * 2;
		return this.WangLine.substring(dindex, dindex + 2)
	}
	/**
	 * @description 获取大运干支
	 * @param {int} theIndex
	 * @return {GanZhi}
	 */
	getDaYun(theIndex : number) : GanZhi {
		var dstart = GanZhi.getHuaJiaByIndex(this.MonthGZ.TianGan, this.MonthGZ.DiZhi);
		if (this.getDaYunSort()) {
			let ganzi = GanZhi.getGanzhiTuple((dstart + theIndex + 1) % 60);
			return new GanZhi(ganzi[0], ganzi[1]);
		} else {
			let ganzi = GanZhi.getGanzhiTuple((60 + dstart - theIndex - 1) % 60);
			return new GanZhi(ganzi[0], ganzi[1]);
		}
	}
	/** 返回虚岁(周岁加1), 如果为负数, 按周岁从-1开始 */
	getVAge() {
		let age = dateUtil.GetDaysFrom(this.Date, new Date());
		if (age < 0) return age;
		return age + 1;
	}
	Swap() {
		if (!this.OtherSiZhu) return this;
		let sz = new SiZhu(this.Date, this.ChinaDate, this.IsMan, this.OtherSiZhu.YearGZ, this.OtherSiZhu.MonthGZ, this.OtherSiZhu.DayGZ, this.OtherSiZhu.HourGZ);
		sz.OtherJieQiIndex = this.OtherJieQiIndex;
		sz.OtherSiZhu = this;
		sz.OtherSiZhu.OtherSiZhu = undefined;
		return sz;
	}
	/**
	 * @description 从公历日期(包含时辰)获取四柱信息
	 * @param {Date} date 公历日期
	 * @param {Boolean} hasHour 是否计算时辰
	 * @return {SiZhu}
	 */
	static getSiZhu(date : Date, hasHour : boolean, theIsMan : boolean) : SiZhu {
		let after23 = false;
		let hour = date.getHours();
		if (hour == 23) after23 = true;
		let dgz = GanZhi.getGanzhiFromDate(date, after23);
		let hgz : GanZhi = undefined;
		if (hasHour) hgz = GanZhi.createHourGanzhi(dgz.TianGan, dateUtil.getHour12From24(hour));
		let jq = JieQi.getJieQiIndexByDate(date);
		let dizhiYear = date.getFullYear();
		if (jq < 2) {
			dizhiYear--;
			jq += 24;
		}
		let ygz = GanZhi.createYearGanzhi(dizhiYear);
		let mgz = GanZhi.createMonthGanzhi(ygz.TianGan, JieQi.getJieqiMonthFromJieqiIndex(jq));
		let chdate : ChinaDate;
		try {
			chdate = ChinaDate.getChinaDate(date);
		} catch (error) {
			//TODO handle the exception
		}
		return new SiZhu(date, chdate, theIsMan, ygz, mgz, dgz, hgz);
		// 	var did = dateUtil.getJieQiMonthArray(theDate, hasHour)
		// 	var y: number, m: number;
		// 	let ygz: GanZhi;
		// 	let mgz: GanZhi;
		// 	let dgz: GanZhi;
		// 	if (did[0] < 0) {
		// 		y = theDate.getFullYear() - 1;
		// 		m = 12 + did[0];
		// 	} else {
		// 		y = theDate.getFullYear();
		// 		m = did[0];
		// 	};
		// 	ygz = GanZhi.getYearGanZhi(y);
		// 	var mtg = (((ygz.TianGan % 5) + 1) * 2) % 10;
		// 	mgz = new GanZhi((mtg + m) % 10, (m + 2) % 12);
		// 	//var ddays1 = ((theDate.valueOf() - dateUtil.DayGanZhiZero.valueOf()) / (1000 * 60 * 60 * 24));
		// 	var ddays = dateUtil.GetDaysFrom(dateUtil.DayGanZhiZero, theDate);
		// 	if (theDate.getHours() >= 23) {
		// 		ddays++
		// 	}

		// 	dgz = GanZhi.getGanzhiByHuajia(ddays % 60);
		// 	let hgz: GanZhi | undefined;
		// 	if (hasHour) {
		// 		var h = (dgz.TianGan % 5) * 2;
		// 		hgz = new GanZhi((h + theChinaDate.Hour) % 10, theChinaDate.Hour);
		// 	};
		// 	var sz = new SiZhu(theDate, theChinaDate, theIsMan, ygz, mgz, dgz, hgz);
		// 	if (did.length > 1) {
		// 		if (did[1] < 0) {
		// 			y = theDate.getFullYear() - 1;
		// 			m = 12 + did[1];
		// 		} else {
		// 			y = theDate.getFullYear();
		// 			m = did[1];
		// 		};

		// 		ygz = GanZhi.getYearGanZhi(y);
		// 		var mtg = (((ygz.TianGan % 5) + 1) * 2) % 10;
		// 		mgz = new GanZhi((mtg + m) % 10, (m + 2) % 12);
		// 		hgz = undefined;
		// 		if (hasHour) {
		// 			var h = (dgz.TianGan % 5) * 2;
		// 			hgz = new GanZhi((h + theChinaDate.Hour) % 10, theChinaDate.Hour);
		// 		};
		// 		var other = new SiZhu(theDate, theChinaDate, theIsMan, ygz, mgz, dgz, hgz);
		// 		sz.OtherSiZhu = other;
		// 		sz.OtherJieQiIndex = (Math.max(did[0], did[1]) + 1) * 2;
		// 	} else {
		// 		sz.OtherJieQiIndex = undefined;
		// 		sz.OtherSiZhu = undefined;
		// 	}
		// 	return sz;
	}
	getText() {
		return this.YearGZ.getText() + " " + this.MonthGZ.getText() + " " + this.DayGZ.getText() + (this.HourGZ ? " " + this.HourGZ.getText() : "");
	}
}